package sys_serv

import (
	"strconv"
	"strings"
	"ubt-rbac-service/internal/app/model"
	"ubt-rbac-service/internal/app/model/sys_mod"
	"ubt-rbac-service/internal/app/util"
	"ubt-rbac-service/internal/core/logger"
)

type sysModule struct{}

var SysModServ = sysModule{}

// Add 新增模块
func (s *sysModule) Add(req *sys_mod.SysModSaveReq) *model.Result {
	sqlStr := "INSERT INTO sys_module(mod_name, mod_code, url, showed, mod_pos, parent_id, sort, states, add_time) " +
		"VALUES ($1, $2, $3, $4, $5, $6, $7, 1, EXTRACT(EPOCH FROM NOW()))"
	retCode, retMsg := util.CudData(sqlStr, req.ModName, req.ModCode, req.Url, req.Showed, req.ModPos, req.ParentId, req.Sort)
	return &model.Result{RetCode: retCode, RetMsg: retMsg}
}

// Exists 判断模块编码是否存在
func (s *sysModule) Exists(req *sys_mod.SysModExtVo) bool {
	sqlStr := "SELECT COUNT(1) AS nums FROM sys_module WHERE states=1 AND mod_code=$1"
	param := make([]interface{}, 0)
	param = append(param, req.ModCode)
	if req.ModId != "" {
		sqlStr += " AND mod_id!=$2"
		param = append(param, req.ModId)
	}
	if dbMap, err := util.GetOne(sqlStr, param...); err == nil && len(dbMap) > 0 {
		if dbMap["nums"].(int64) > 0 {
			return true
		}
	}
	return false
}

// Update 修改模块
func (s *sysModule) Update(req *sys_mod.SysModSaveReq) *model.Result {
	sqlStr := "UPDATE sys_module SET mod_name=$1, mod_code=$2, url=$3, showed=$4, mod_pos=$5, parent_id=$6, sort=$7, " +
		"upd_time=EXTRACT(EPOCH FROM NOW()) WHERE mod_id=$8"
	retCode, retMsg := util.CudData(sqlStr, req.ModName, req.ModCode, req.Url, req.Showed, req.ModPos, req.ParentId, req.Sort, req.ModId)
	return &model.Result{RetCode: retCode, RetMsg: retMsg}
}

// Deletes 删除模块
func (s *sysModule) Deletes(req *sys_mod.SysModDelsReq) *model.Result {
	var (
		// param 数据库表操作的参数数组
		param []interface{}
		// idList 编号数组
		idList []string
		// q 拼接SQL的点位符字符串，如$1, $2……
		q string
		// 索引序号
		n = 0
	)
	// 将字符串转换成数组
	idArr := strings.Split(req.ModIds, ",")
	// 获取所有的模块编号
	modList := s.selMods()
	// 递归遍历每个模块下的子模块及子孙模块，最后返回给idList编号数组
	for _, curId := range idArr {
		idList = append(idList, curId)
		idList = s.getIds(modList, curId, idList)
	}
	// 拼接SQL
	for _, curId := range idList {
		n++
		q += "$" + strconv.Itoa(n) + ","
		param = append(param, curId)
	}
	q = q[:len(q)-1]
	sqlStr := "UPDATE sys_module SET states=2, upd_time=EXTRACT(EPOCH FROM NOW()) WHERE mod_id IN (" + q + ")"
	// 执行SQL，并返回结果
	retCode, retMsg := util.CudData(sqlStr, param...)
	return &model.Result{RetCode: retCode, RetMsg: retMsg}
}

// selMods 获取所有模块的编号
func (s *sysModule) selMods() []*sys_mod.SysModSelRes {
	sqlStr := "SELECT mod_id, parent_id FROM sys_module WHERE states=1 ORDER BY mod_code"
	// 连接数据库
	db := util.GetDbConn()
	// 用原生查询数据，之所以不用封装好的查询方法，是因为需要转换为作二次调用的结构体对象，而封装好的直接返回了数据结构，而不是结构体对象。
	if rows, err := db.Query(sqlStr); err == nil {
		bo := &sys_mod.SysModSelRes{}
		var bos []*sys_mod.SysModSelRes
		for rows.Next() {
			// 查询到的数据转换为结构体
			err = rows.Scan(&bo.ModId, &bo.ParentId)
			if err == nil {
				bos = append(bos, bo)
				bo = &sys_mod.SysModSelRes{}
			} else {
				logger.Error("模块信息封装失败。" + err.Error())
				return nil
			}
		}
		return bos
	} else {
		return nil
	}
}

// getIds 递归遍历获取子级模块编号
func (s *sysModule) getIds(list []*sys_mod.SysModSelRes, id string, newList []string) []string {
	for _, item := range list {
		if id == item.ParentId {
			newList = append(newList, item.ModId)
			newList = s.getIds(list, item.ModId, newList)
		}
	}
	return newList
}

// One 获取模块详情
func (s *sysModule) One(modId string) *model.Result {
	sqlStr := "SELECT a.mod_id, a.mod_name, a.mod_code, a.url, a.showed, a.mod_pos, a.parent_id, " +
		"(CASE WHEN a.parent_id='111111111111111111111' THEN '一级模块' ELSE b.mod_name END) AS parent_name, " +
		"(CASE WHEN a.parent_id='111111111111111111111' THEN '10000000' ELSE b.mod_code END) AS parent_code, " +
		"a.sort, a.states, a.add_time, a.upd_time " +
		"FROM sys_module a " +
		"LEFT JOIN sys_module b ON b.states=1 AND a.parent_id=b.mod_id " +
		"WHERE a.mod_id=$1"
	if dbMap, err := util.GetOne(sqlStr, modId); err == nil && len(dbMap) > 0 {
		return &model.Result{RetCode: 1001, RetMsg: "ok", RetData: dbMap}
	} else {
		return &model.Result{RetCode: 1000, RetMsg: "暂无内容"}
	}
}

// List 获取模块树状列表
func (s *sysModule) List() *model.Result {
	sqlStr := "SELECT mod_id, mod_name, mod_code, url, showed, mod_pos, parent_id, sort FROM sys_module WHERE states=1 ORDER BY sort"
	db := util.GetDbConn()
	if rows, err := db.Query(sqlStr); err == nil {
		bo := &sys_mod.SysModListRes{}
		var bos []*sys_mod.SysModListRes
		for rows.Next() {
			err = rows.Scan(&bo.ModId, &bo.ModName, &bo.ModCode, &bo.Url, &bo.Showed, &bo.ModPos, &bo.ParentId, &bo.Sort)
			if err == nil {
				bos = append(bos, bo)
				bo = &sys_mod.SysModListRes{}
			} else {
				logger.Error("模块信息封装失败。" + err.Error())
				return &model.Result{RetCode: 1002, RetMsg: "模块信息封装失败"}
			}
		}
		var newList []*sys_mod.SysModListRes
		if len(bos) > 0 {
			var level uint8 = 1
			for _, item := range bos {
				if "111111111111111111111" == item.ParentId {
					item.ModLevel = level
					newList = append(newList, item)
					newList = s.sortChildMod(bos, item.ModId, newList, level)
				}
			}
		}
		return &model.Result{RetCode: 1001, RetMsg: "ok", RetData: newList}
	} else {
		return &model.Result{RetCode: 1000, RetMsg: "暂无内容"}
	}
}

// Select 获取模块树状列表
func (s *sysModule) Select() *model.Result {
	sqlStr := "SELECT mod_id, mod_name, mod_code, parent_id, sort FROM sys_module WHERE states=1 ORDER BY sort"
	db := util.GetDbConn()
	if rows, err := db.Query(sqlStr); err == nil {
		bo := &sys_mod.SysModListRes{}
		var bos []*sys_mod.SysModListRes
		for rows.Next() {
			err = rows.Scan(&bo.ModId, &bo.ModName, &bo.ModCode, &bo.ParentId, &bo.Sort)
			if err == nil {
				bos = append(bos, bo)
				bo = &sys_mod.SysModListRes{}
			} else {
				logger.Error("模块信息封装失败。" + err.Error())
				return &model.Result{RetCode: 1002, RetMsg: "模块信息封装失败"}
			}
		}
		var newList []*sys_mod.SysModListRes
		if len(bos) > 0 {
			var level uint8 = 1
			for _, item := range bos {
				if "111111111111111111111" == item.ParentId {
					item.ModLevel = level
					newList = append(newList, item)
					newList = s.sortChildMod(bos, item.ModId, newList, level)
				}
			}
		}
		return &model.Result{RetCode: 1001, RetMsg: "ok", RetData: newList}
	} else {
		return &model.Result{RetCode: 1000, RetMsg: "暂无内容"}
	}
}

// sortChildMod 将模块按树状排序
func (s *sysModule) sortChildMod(list []*sys_mod.SysModListRes, modId string, newList []*sys_mod.SysModListRes, level uint8) []*sys_mod.SysModListRes {
	level++
	for _, item := range list {
		if modId == item.ParentId {
			item.ModLevel = level
			newList = append(newList, item)
			newList = s.sortChildMod(list, item.ModId, newList, level)
		}
	}
	return newList
}

// Tree 获取模块树状列表
func (s *sysModule) Tree() *model.Result {
	sqlStr := "SELECT mod_id sel_id, mod_name sel_name, mod_code sel_code, parent_id sel_pid, false chked FROM sys_module WHERE states=1 ORDER BY mod_code"
	db := util.GetDbConn()
	if rows, err := db.Query(sqlStr); err == nil {
		bo := &sys_mod.SysModTreeRes{}
		var bos []*sys_mod.SysModTreeRes
		for rows.Next() {
			err = rows.Scan(&bo.SelId, &bo.SelName, &bo.SelCode, &bo.SelPid, &bo.Chked)
			if err == nil {
				bos = append(bos, bo)
				bo = &sys_mod.SysModTreeRes{}
			} else {
				logger.Error("模块信息封装失败。" + err.Error())
				return &model.Result{RetCode: 1002, RetMsg: "模块信息封装失败"}
			}
		}
		tree := s.buildTree(bos, "111111111111111111111")
		return &model.Result{RetCode: 1001, RetMsg: "ok", RetData: tree}
	} else {
		return &model.Result{RetCode: 1000, RetMsg: "暂无内容"}
	}
}

// buildTree 创建模块的树状列表
func (s *sysModule) buildTree(list []*sys_mod.SysModTreeRes, parentId string) []*sys_mod.SysModTreeRes {
	var tree []*sys_mod.SysModTreeRes
	if len(list) > 0 {
		for _, child := range list {
			if parentId == child.SelPid {
				tree = append(tree, s.findChild(child, list))
			}
		}
	}
	return tree
}

// findChild 组织子级模块列表数据
func (s *sysModule) findChild(child *sys_mod.SysModTreeRes, list []*sys_mod.SysModTreeRes) *sys_mod.SysModTreeRes {
	if len(list) > 0 {
		for _, curChild := range list {
			if child.SelId == curChild.SelPid {
				child.Children = append(child.Children, s.findChild(curChild, list))
			}
		}
	}
	return child
}

// Sort 获取模块数量，用于排序
func (s *sysModule) Sort(parentId string) *model.Result {
	sqlStr := "SELECT COUNT(1)+1 AS nums FROM sys_module WHERE states=1 AND parent_id=$1"
	if dbMap, err := util.GetOne(sqlStr, parentId); err == nil && len(dbMap) > 0 {
		return &model.Result{RetCode: 1001, RetMsg: "ok", RetData: dbMap["nums"]}
	} else {
		return &model.Result{RetCode: 1000, RetMsg: "暂无内容"}
	}
}

// Menu 获取模块树状菜单
func (s *sysModule) Menu(modCodes string) *model.Result {
	sqlStr := "SELECT mod_id, mod_name, url, 'chevron_down' icon, false actived, parent_id, mod_pos FROM sys_module WHERE states=1 AND showed=1 AND $1 LIKE '%'||mod_code||'%' ORDER BY sort"
	db := util.GetDbConn()
	if rows, err := db.Query(sqlStr, modCodes); err == nil {
		bo := &sys_mod.SysModMenuRes{}
		var bos []*sys_mod.SysModMenuRes
		for rows.Next() {
			err = rows.Scan(&bo.ModId, &bo.ModName, &bo.Url, &bo.Icon, &bo.Actived, &bo.ParentId, &bo.ModPos)
			if err == nil {
				bos = append(bos, bo)
				bo = &sys_mod.SysModMenuRes{}
			} else {
				logger.Error("模块信息封装失败。" + err.Error())
				return &model.Result{RetCode: 1002, RetMsg: "模块信息封装失败"}
			}
		}
		tree := s.buildMenu(bos, "111111111111111111111")
		return &model.Result{RetCode: 1001, RetMsg: "ok", RetData: tree}
	} else {
		return &model.Result{RetCode: 1000, RetMsg: "暂无内容"}
	}
}

// buildMenu 创建模块的树状列表
func (s *sysModule) buildMenu(list []*sys_mod.SysModMenuRes, parentId string) []*sys_mod.SysModMenuRes {
	var tree []*sys_mod.SysModMenuRes
	if len(list) > 0 {
		for _, child := range list {
			if parentId == child.ParentId {
				tree = append(tree, s.findChildMenu(child, list))
			}
		}
	}
	return tree
}

// findChildMenu 组织子级模块列表数据
func (s *sysModule) findChildMenu(child *sys_mod.SysModMenuRes, list []*sys_mod.SysModMenuRes) *sys_mod.SysModMenuRes {
	if len(list) > 0 {
		for _, curChild := range list {
			if child.ModId == curChild.ParentId {
				child.Children = append(child.Children, s.findChildMenu(curChild, list))
			}
		}
	}
	return child
}
